---
title: Actions
description: Reatom actions and code organization
---

import { Aside } from '@astrojs/starlight/components'

Action is a base Reatom primitive that **increases the quality of your code** in many ways: organization and readability, debugability, extensibility.

The beauty of Reatom is that you don't need to use actions for simple updates, like `(value) => myAtom.set(value)`. Actions are useful for complex operations, like data mappings, API calls and other side effects.

You can call actions anywhere just like regular functions. You can describe its parameters just like with regular functions. You can type your action function with TypeScript generics as usual. `action` itself is a simple decorator which adds some extra features to your function, but does not limit you in any way.

```ts
import { atom, action } from '@reatom/core'

export const list = atom([])
const isListLoading = atom(false)

const loadList = action(async (page: number) => {
  isListLoading.set(true)
  try {
    const response = await fetch(`/api/list?page=${page}`)
    const payload = await response.json()
    list.set(payload)
  } finally {
    isListLoading.set(false)
  }
})

loadList(1) // Promise
```

Note that `action` is an optional feature and not required in your code, but it is always nice to use it.

## Naming

Most Reatom units accept an optional name for debugging purposes. We highly recommend using it, as it helps to debug the runtime dataflow.

```ts /'list'|'isListLoading'|'loadList'/
export const list = atom([], 'list')
const isListLoading = atom(false, 'isListLoading')

const loadList = action(async (page: number) => {
  // ...
}, 'loadList')
```

That's better!

<Aside type="tip">
  If you use some LLM code assistant it will help you to write related names for
  you, but we have an eslint plugin to automate it. You can find the plugin and
  useful logger in [out tooling section](/start/tooling/).
</Aside>

## Extend

Under the hood action is a special type of atom; it gives us the ability to reuse many patterns and extensions. In the next chapter, we will get to know extensions more closely, but for now, let's learn how to better organize our code.

`extend` accept a callback with the processed target, which return an object to assign to the target.

```ts /target/
import { atom, action } from '@reatom/core'

export const list = atom([], 'list').extend((target) => {
  const isLoading = atom(
    false,
    // compute the name from the target
    `${target.name}.isLoading`,
  )
  const load = action(async (page: number) => {
    // ...
  }, `${target.name}.load`)

  // return things that you want to assign to the current atom
  return {
    isLoading,
    load,
  }
})
```

Now you can access your states in a clean and readable way:

```tsx {"   You can use regular hooks in reatomComponent!": 6-7} title="src/component/Paging.tsx"
import React from 'react'
import { reatomComponent } from '@reatom/react'
import { list } from './model'

const Paging = reatomComponent(() => {
  
  const [page, setPage] = React.useState(1)

  React.useEffect(() => {
    list.load(page)
  }, [page])

  const isLoading = list.isLoading()

  return (
    <button onClick={() => setPage((page) => page + 1)} disabled={isLoading}>
      {isLoading ? 'Loading...' : 'Next page'}
    </button>
  )
})

const List = reatomComponent(() => (
  <section>
    <Paging />
    {list().map(/* ... */)}
  </section>
))
```

Awesome, now you can couple relative states with relative components without a props drilling!

But this is just the beginning, `.extend` can give us much more! Check out the next section to learn more about it.
